package day28.homework;

/**
 * 包子铺测试类
 * 演示生产者-消费者模式在线程同步中的应用
 * 
 * HashMap：哈希表实现，无序
 * LinkedHashMap：保持插入顺序
 * TreeMap：按键的自然顺序或自定义顺序排序
 * 
 * 这个类用于测试包子铺的生产和消费过程
 * 创建一个包子师傅（生产者）和三个顾客（消费者）
 * 演示线程间的同步和通信机制
 * 
 * 多线程相关知识点：
 * 1. 线程创建：通过Thread类创建线程对象
 * 2. 线程启动：调用start()方法启动线程
 * 3. 线程等待：使用join()方法等待线程执行完毕
 * 4. 线程休眠：使用Thread.sleep()方法使线程暂停执行
 * 5. 线程同步：通过共享对象实现线程间的协调工作
 */
public class BunShopTest {
    /**
     * 主方法，程序入口
     * 创建并启动所有线程，演示包子铺的运营过程
     * 
     * 线程执行流程详解：
     * 1. 创建共享资源（包子铺对象）
     * 2. 创建生产者线程（包子师傅）
     * 3. 创建消费者线程（三个顾客）
     * 4. 按特定顺序启动线程
     * 5. 等待所有消费者线程执行完毕
     * 6. 停止生产者线程
     * 
     * 线程同步机制详解：
     * 1. 共享资源：所有线程共享同一个BunShop对象
     * 2. 同步方法：BunShop类中的makeBun和buyBun方法都是同步方法
     * 3. 等待/通知：通过wait()/notifyAll()实现线程间的等待和通知
     * 4. 线程控制：通过join()方法控制线程的执行顺序
     * 
     * @param args 命令行参数
     * @throws InterruptedException 当线程在等待过程中被中断时抛出此异常
     */
    public static void main(String[] args) throws InterruptedException {
        System.out.println("包子铺开始营业");
        
        // 创建包子铺，作为共享资源
        // 所有线程（包子师傅和顾客）都会访问这个对象
        // 通过这个共享对象实现线程间的同步和通信
        BunShop bunShop = new BunShop();
        
        // 创建包子师傅，作为生产者
        // BunChef实现了Runnable接口，包含包子制作的逻辑
        BunChef chef = new BunChef(bunShop);
        // 将包子师傅包装成线程对象，并设置线程名称为"包子师傅"
        // Thread类的构造方法可以接受Runnable对象和线程名称
        Thread chefThread = new Thread(chef, "包子师傅");
        
        // 创建三个顾客，作为消费者
        // 顾客1偏好肉馅包子
        Customer customer1 = new Customer(bunShop, "顾客1", Bun.Flavor.MEAT);
        // 顾客2偏好蔬菜馅包子
        Customer customer2 = new Customer(bunShop, "顾客2", Bun.Flavor.VEGETABLE);
        // 顾客3偏好肉馅包子
        Customer customer3 = new Customer(bunShop, "顾客3", Bun.Flavor.MEAT);
        
        // 将顾客包装成线程对象，并设置线程名称
        Thread customerThread1 = new Thread(customer1, "顾客1");
        Thread customerThread2 = new Thread(customer2, "顾客2");
        Thread customerThread3 = new Thread(customer3, "顾客3");
        
        // 启动包子师傅线程，开始制作包子
        // 调用start()方法启动线程，线程进入就绪状态等待CPU调度
        // 线程实际执行的是BunChef类的run()方法
        chefThread.start();
        
        // 等待一段时间，让师傅先制作一些包子
        // 这样可以避免顾客一开始就没有包子可买的情况
        // Thread.sleep()方法使主线程暂停执行指定时间（毫秒）
        // 在这段时间内，包子师傅线程会持续制作包子
        Thread.sleep(2000);
        
        // 启动顾客线程，开始购买包子
        // 三个顾客线程几乎同时启动，会竞争访问包子铺对象
        // 由于buyBun方法是同步方法，同一时间只有一个顾客能购买包子
        customerThread1.start();
        customerThread2.start();
        customerThread3.start();
        
        // 等待所有顾客买完包子
        // 使用join()方法确保主线程等待所有子线程执行完毕
        // join()方法会使主线程阻塞，直到目标线程执行完毕
        // 这样可以确保所有顾客都买到包子后才继续执行
        customerThread1.join();
        customerThread2.join();
        customerThread3.join();
        
        // 停止包子师傅
        // 设置标志位使包子师傅线程退出循环
        // stop()方法会修改BunChef对象中的running标志位
        // 包子师傅线程检测到标志位变化后会自然退出run()方法
        chef.stop();
        
        System.out.println("包子铺结束营业");
    }
}